home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / audio / rock / libsample.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  26.1 KB  |  1,166 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.  *    libsample -
  19.  *        read and write samples of sound.
  20.  *
  21.  *    exports:
  22.  *        sample *readsample(name);
  23.  *         writesample(s,name);
  24.  *
  25.  *        printsample(s);
  26.  *
  27.  *        playsample(s);
  28.  *        playsubsample(s,start,finish);
  29.  *        flushsample();
  30.  *
  31.  *        expandsample(s);
  32.  *        minmaxsample(s,min,max);
  33.  *        scalesample(s,gain);
  34.  *        stereoizesample(s,mag);
  35.  *
  36.  *        freesample(s);
  37.  *        sample *clonesample(s);
  38.  *
  39.  *        sample *tonesample(nsamples);
  40.  *        sample *subsample(s,begin,end);
  41.  *        sample *extendsample(s,len);
  42.  *        reversesample(s);
  43.  *
  44.  *        beginnotes();
  45.  *        playnote(s,ftime,amplitude);
  46.  *        endnotes();
  47.  *        setbpm(b)
  48.  *        flushnotes(ftime)
  49.  *        sethumanize(time,amp)
  50.  *
  51.  *            Paul Haeberli - 1991
  52.  */
  53. #include "math.h"
  54. #include "stdio.h"
  55. #include "fcntl.h"
  56. #include "sys/types.h"
  57. #include "malloc.h"
  58. #include "aiff.h"
  59. #include "audio.h"
  60. #include "sample.h"
  61.  
  62. int ilimit(min,v,max)
  63. int min,v,max;
  64. {
  65.     if(v<min)
  66.     return min;
  67.     if(v>max)
  68.     return max;
  69.     return v;
  70. }
  71.  
  72. /*
  73.  *    code to READ an aiff file
  74.  *
  75.  *
  76.  */
  77. static void
  78. copy_audio_samps(ssnd_chunk_t *ssnd_data, 
  79.                 audio_params_t *audio_params,
  80.                 sample *s);
  81.  
  82. typedef union 
  83. {
  84.     unsigned char b[2];
  85.     short         s;
  86. } align_short_t;
  87.  
  88. typedef union 
  89. {
  90.     unsigned char b[4];
  91.     long         l;
  92. } align_long_t;
  93.  
  94. /*
  95.  * local subroutines
  96.  */
  97. void parse_cmd_line(int argc, char **argv);
  98. static int  read_chunk_header(chunk_header_t *);
  99. static void read_form_chunk(chunk_header_t *, form_chunk_t *);
  100. static void read_comm_chunk(chunk_header_t *,comm_chunk_t *, 
  101.                       audio_params_t *audio_params);
  102. static void read_ssnd_chunk(chunk_header_t *, ssnd_chunk_t *);
  103. static void skip_chunk(chunk_header_t *);
  104.  
  105. /*
  106.  * globals 
  107.  */
  108. static char *filename;     /* input file name */
  109. static int fd;            /* input file descriptor */
  110. static char *myname;       /* name of this program */
  111. static long bytes_per_samp;
  112. static long samps_per_frame;
  113. static long frames_per_sec;
  114. static long total_frames;
  115. static long total_samps;
  116. static long total_samp_bytes;
  117. static long total_bytes;     /* total bytes in output file */
  118.  
  119. sample *readsample(name)
  120. char *name;
  121. {
  122.     int i,n;
  123.     char buf[8];
  124.     chunk_header_t chunk_header;
  125.     form_chunk_t form_data;
  126.     comm_chunk_t comm_data;
  127.     ssnd_chunk_t ssnd_data;
  128.     audio_params_t audio_params;
  129.     ALport audio_port;
  130.     sample *s;
  131.     
  132.     myname = "readaiff";
  133.     filename = name;
  134.  
  135.     if ((fd = open(filename, O_RDONLY)) < 0) {
  136.         fprintf(stderr, "%s: couldn't open %s\n", myname, filename);
  137.         exit(-1);
  138.     }
  139.  
  140.     if ((n = read_chunk_header(&chunk_header)) != CHUNK_HEADER) {
  141.         fprintf(stderr, "%s: failed to read FORM chunk header\n", myname);
  142.         exit(-1);
  143.     }
  144.     if (strncmp(chunk_header.id, "FORM", 4)) {        /* form container */
  145.         fprintf(stderr, "%s: couldn't find FORM chunk id\n", myname);
  146.         exit(-1);
  147.     }
  148.     read_form_chunk(&chunk_header, &form_data);
  149.  
  150.     /*
  151.      * loop on the local chunks
  152.      */
  153.     while (1) {
  154.         if ((n = read_chunk_header(&chunk_header)) == 0)
  155.             goto loop_done;
  156.         else if (n != CHUNK_HEADER) {
  157.             fprintf(stderr, "%s: failed to read a chunk header\n", myname);
  158.             exit(-1);
  159.         }
  160.         if (!strncmp(chunk_header.id, "COMM", 4))    /* common */
  161.             read_comm_chunk(&chunk_header, &comm_data, &audio_params);
  162.         else if (!strncmp(chunk_header.id, "SSND", 4))  /* sound data */
  163.             read_ssnd_chunk(&chunk_header, &ssnd_data);
  164.         else if ((!strncmp(chunk_header.id, "MARK", 4))  /* marker */
  165.               || (!strncmp(chunk_header.id, "INST", 4))  /* instrument */
  166.               || (!strncmp(chunk_header.id, "APPL", 4))   /* appl specific */
  167.               || (!strncmp(chunk_header.id, "MIDI", 4))  /* midi data */
  168.               || (!strncmp(chunk_header.id, "AESD", 4))   /* audio  rec */
  169.               || (!strncmp(chunk_header.id, "COMT", 4))   /* comments */
  170.               || (!strncmp(chunk_header.id, "NAME", 4))   /* text */
  171.               || (!strncmp(chunk_header.id, "AUTH", 4))   /* text */
  172.               || (!strncmp(chunk_header.id, "(c) ", 4))   /* text */
  173.               || (!strncmp(chunk_header.id, "ANNO", 4))) {   /* text */
  174.             skip_chunk(&chunk_header);
  175.         } else {
  176.             fprintf(stderr,
  177.             "%s: bad chunk id  0x%02x%02x%02x%02x\n",
  178.                      myname, chunk_header.id[0],chunk_header.id[1],
  179.                      chunk_header.id[2], chunk_header.id[3]);
  180.         }
  181.     } /* while */
  182.  
  183. loop_done:
  184.  
  185.     s = (sample *)malloc(sizeof(struct sample));
  186.     /*
  187.      * save the sample data
  188.      */
  189.     s->samprate = audio_params.samprate;
  190.     s->sampwidth = audio_params.sampwidth;
  191.     s->nchannels = audio_params.nchannels;
  192.     if(s->sampwidth != 2) {
  193.     fprintf(stderr,"samplewidth must be 2 bytes for now\n");
  194.     exit(1);
  195.     }
  196.     if(s->nchannels != 2) {
  197.     fprintf(stderr,"nchannels must be 2 (stereo) for now\n");
  198.     exit(1);
  199.     }
  200.     copy_audio_samps(&ssnd_data, &audio_params, s);
  201.     close(fd);
  202.     return s;
  203. }
  204.  
  205. /*
  206.  * R E A D _ C H U N K _ H E A D E R
  207.  */
  208. static int
  209. read_chunk_header(chunk_header_t *chunk_header)
  210. {
  211.     align_long_t align_long;
  212.     char buf[CHUNK_HEADER];
  213.     int i, n;
  214.  
  215.     if ((n = read(fd, buf, CHUNK_HEADER)) != CHUNK_HEADER)
  216.         return(n);
  217.     for (i=0; i<4; i++)
  218.         chunk_header->id[i] = buf[i];
  219.     for (i=0; i<4; i++)
  220.         align_long.b[i] = buf[i+4];
  221.     chunk_header->size = align_long.l;
  222.     return(CHUNK_HEADER);
  223. }
  224.  
  225. static void
  226. read_form_chunk(chunk_header_t *chunk_header, form_chunk_t *form_data)
  227. {
  228.     int n;
  229.     char buf[FORM_CHUNK_DATA];
  230.  
  231.     if (chunk_header->size < 0) {
  232.         fprintf(stderr, "%s: invalid FORM chunk data size %d\n",myname,
  233.                                  chunk_header->size);
  234.         exit(-1);
  235.     } else if (chunk_header->size == 0) {
  236.         fprintf(stderr,"%s: FORM chunk data size = 0\n", myname);
  237.         exit(0);
  238.     }
  239.     if ((n = read(fd, buf, FORM_CHUNK_DATA)) != FORM_CHUNK_DATA) {
  240.         fprintf(stderr, "%s: couldn't read AIFF identifier from %s\n",
  241.                            myname, filename);
  242.         exit(-1);
  243.     }
  244.     if (strncmp(buf, "AIFF", 4)) {
  245.        fprintf(stderr, "%s: %s does not have an AIFF identifier\n",
  246.                   myname, filename);
  247.        exit(-1);
  248.     }
  249. }
  250.  
  251.  
  252. /*
  253.  * R E A D _ C O M M _ C H U N K
  254.  */
  255. static void
  256. read_comm_chunk(chunk_header_t *chunk_header, 
  257.                     comm_chunk_t *comm_data,
  258.                     audio_params_t *audio_params)
  259. {
  260.     int n;
  261.     char *buf, *bufp;
  262.     int i;
  263.     align_short_t align_short;
  264.     align_long_t  align_long;
  265.  
  266.     buf = malloc(COMM_CHUNK_DATA + 1); /* one extra loc at the end */
  267.  
  268.     if ((n = read(fd,  buf, COMM_CHUNK_DATA)) != COMM_CHUNK_DATA) {
  269.         fprintf(stderr, 
  270.         "%s: failed to read COMM chunk data. Expected %d bytes, got %d.\n",
  271.             myname, COMM_CHUNK_DATA, n); 
  272.         exit(-1);
  273.     }
  274.     bufp = buf;
  275.     for (i=0; i<2; i++)
  276.        align_short.b[i] = *bufp++;
  277.     comm_data->nchannels = align_short.s;
  278.     for (i=0; i<4; i++) 
  279.        align_long.b[i]  = *bufp++;
  280.     comm_data->nsampframes = align_long.l;
  281.     for (i=0; i<2; i++)
  282.        align_short.b[i] = *bufp++;
  283.     comm_data->sampwidth = align_short.s; 
  284.     /*
  285.      * the sample rate value from the common chunk is an 80-bit IEEE extended
  286.      * floating point number:
  287.      * [s bit] [15 exp bits (bias=16383)] [64 mant bits (leading 1 not hidden)]
  288.      *
  289.      * turns out we can just grab bytes 2 and 3 (if bytes numbered 0 ... 9)
  290.      * and cast them as an integer: the integer value equals the sample rate
  291.      */
  292.     for (i=0; i<2; i++)
  293.         bufp++;
  294.     align_short.b[0] = *bufp++;
  295.     align_short.b[1] = *bufp++;
  296.     for (i=0; i<6; i++)
  297.         bufp++;
  298.     comm_data->samprate = (unsigned short)align_short.s;
  299.  
  300.     switch (comm_data->samprate) {
  301.         case 48000:
  302.         audio_params->samprate = AL_RATE_48000;        
  303.         break;
  304.     case 44100:
  305.         audio_params->samprate = AL_RATE_44100;
  306.         break;
  307.     case 32000:
  308.         audio_params->samprate = AL_RATE_32000;
  309.         break;
  310.     case 16000:
  311.         audio_params->samprate = AL_RATE_16000;
  312.         break;
  313.     case  8000:
  314.         audio_params->samprate = AL_RATE_8000;
  315.         break;
  316.         default:
  317.                 fprintf(stderr,"%s: can't set output sample rate to %d\n",
  318.                             myname, audio_params->samprate);
  319.         audio_params->samprate = AL_RATE_48000;        
  320.     }
  321.     switch (comm_data->nchannels) {
  322.     case 1:
  323.         audio_params->nchannels = AL_MONO;
  324.         break;
  325.     case 2:
  326.         audio_params->nchannels = AL_STEREO;
  327.         break;
  328.     default:
  329.         fprintf(stderr, "%s: can't handle %d channels per frame\n",
  330.                     myname, comm_data->nchannels);
  331.         audio_params->nchannels = AL_STEREO;
  332.     }
  333.     switch (comm_data->sampwidth) {
  334.     case 8:
  335.          audio_params->sampwidth = AL_SAMPLE_8;
  336.         break;
  337.     case 16:
  338.          audio_params->sampwidth = AL_SAMPLE_16;
  339.         break;
  340.     case 24:
  341.          audio_params->sampwidth = AL_SAMPLE_24;
  342.         break;
  343.     default:
  344.         fprintf(stderr, "%s: unsupported sample width %d bits\n",
  345.             myname, comm_data->nchannels);
  346.          audio_params->sampwidth = AL_SAMPLE_16;
  347.     }
  348.     free(buf);
  349. }
  350.  
  351. static void 
  352. read_ssnd_chunk(chunk_header_t *chunk_header, ssnd_chunk_t *ssnd_data)
  353. {
  354.     char buf[SSND_CHUNK_DATA];
  355.     int i;
  356.     align_long_t align_long;
  357.  
  358.     read(fd, buf, SSND_CHUNK_DATA);
  359.     for (i=0; i<4; i++) 
  360.         align_long.b[i] = buf[i];
  361.     ssnd_data->offset = align_long.l;
  362.     for (i=0; i<4; i++)
  363.         align_long.b[i] = buf[i+4];
  364.     ssnd_data->blocksize = align_long.l;
  365.     /*
  366.      * store the offset to the beginning of the audio sample data so that
  367.      * we can come back and play it later
  368.      */ 
  369.     ssnd_data->file_position = lseek(fd, 0, SEEK_CUR);
  370.     ssnd_data->sample_bytes = chunk_header->size - 2*sizeof(long);
  371.  
  372.     /*
  373.      * move the fileptr to the end of the chunk
  374.      */
  375.     lseek(fd, ssnd_data->sample_bytes, SEEK_CUR);
  376. }
  377.  
  378.  
  379. /*
  380.  * COPY_AUDIO_SAMPS
  381.  */
  382. static void
  383. copy_audio_samps(ssnd_chunk_t *ssnd_data, 
  384.                 audio_params_t *audio_params,
  385.                 sample *s)
  386. {
  387.     int num_bufs;
  388.     int leftover_bytes;
  389.     int leftover_samps;
  390.     int leftover_frames;
  391.     int nread;
  392.     int bytes_per_buf;
  393.     int samps_per_buf;
  394.     int samp_count;
  395.     int frame_count;
  396.     int frames_per_buf;
  397.     float secs_per_frame;
  398.     float secs_per_buf;
  399.     float sec_count;
  400.     int i;
  401.     char *sampbuf;
  402.    
  403.     /*
  404.      * decide what size blocks of samples we should read from the
  405.      * AIFF file and pass to ALwritesamps
  406.      */
  407.     switch (audio_params->sampwidth) {
  408.         case AL_SAMPLE_8: 
  409.         bytes_per_samp = 1; 
  410.         break;
  411.         case AL_SAMPLE_16: 
  412.         default:
  413.         bytes_per_samp = 2; 
  414.         break;
  415.     }
  416.     switch (audio_params->nchannels) {
  417.         case AL_MONO: 
  418.         samps_per_frame = 1; 
  419.         break;
  420.         case AL_STEREO: 
  421.         default:
  422.         samps_per_frame = 2; 
  423.         break;
  424.     }
  425.     switch(audio_params->samprate) {
  426.         case AL_RATE_48000: frames_per_sec = 48000; break;
  427.         case AL_RATE_44100: frames_per_sec = 44100; break;
  428.         case AL_RATE_32000: frames_per_sec = 32000; break;
  429.     case AL_RATE_16000: frames_per_sec = 16000; break; 
  430.     case AL_RATE_8000:  frames_per_sec =  8000; break;
  431.     }
  432.     /*
  433.      * make the buffer large enough to hold 1/2 sec of audio frames
  434.      */
  435.     secs_per_frame = 1.0 / ((float)frames_per_sec);
  436.     bytes_per_buf  = bytes_per_samp * samps_per_frame * frames_per_sec / 2;
  437.     samps_per_buf  = bytes_per_buf / bytes_per_samp;
  438.     frames_per_buf = samps_per_buf / samps_per_frame;
  439.     secs_per_buf   = secs_per_frame * frames_per_buf;
  440.     sampbuf = malloc(bytes_per_buf); 
  441.  
  442.     /*
  443.      * figure out how many reads we have to do
  444.      */
  445.     total_samp_bytes = ssnd_data->sample_bytes;
  446.     total_samps      = total_samp_bytes / bytes_per_samp;
  447.     total_frames     = total_samps / samps_per_frame;
  448.     num_bufs         = total_samp_bytes / bytes_per_buf;
  449.     leftover_bytes   = total_samp_bytes % bytes_per_buf;
  450.     leftover_samps   = leftover_bytes / bytes_per_samp;
  451.     leftover_frames  = leftover_samps / samps_per_frame;
  452.  
  453.     /*
  454.      * move the fileptr to the beginning of the sample data
  455.      */
  456.     lseek(fd, ssnd_data->file_position, SEEK_SET);
  457.     s->nsamples = total_samps;
  458.     s->data = (short *)malloc(total_samp_bytes);
  459.     read(fd, s->data, total_samp_bytes);
  460. }
  461.  
  462. /*
  463.  * S K I P _ C H U N K
  464.  */
  465. static void
  466. skip_chunk(chunk_header_t *chunk_header)
  467. {
  468.     lseek(fd, chunk_header->size, SEEK_CUR);
  469. }
  470.  
  471. /*
  472.  *    Stuff to WRITE an aiff file
  473.  *
  474.  */
  475.  
  476. /*
  477.  * local subroutines
  478.  */
  479. static void write_form_chunk(form_chunk_t *);
  480. static void write_comm_chunk(comm_chunk_t *, sample *);
  481. static void write_ssnd_chunk(ssnd_chunk_t *);
  482. static void write_audio(sample *s);
  483. static void update_form_chunk(form_chunk_t *);
  484. static void update_comm_chunk(comm_chunk_t *);
  485. static void update_ssnd_chunk(ssnd_chunk_t *);
  486.  
  487. writesample(s,name)
  488. sample *s;
  489. char *name;
  490. {
  491.     int i,n;
  492.     form_chunk_t form_chunk;
  493.     comm_chunk_t comm_chunk;
  494.     ssnd_chunk_t ssnd_chunk;
  495.     
  496.     myname = "writesample";
  497.     filename = name;
  498.     if ((fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) {
  499.     fprintf(stderr, "%s: couldn't open %s\n", myname, filename);
  500.     exit(-1);
  501.     }
  502.     write_form_chunk(&form_chunk);
  503.     write_comm_chunk(&comm_chunk, s);
  504.     write_ssnd_chunk(&ssnd_chunk);
  505.     write_audio(s);
  506.     total_bytes = FORM_CHUNK + COMM_CHUNK + SSND_CHUNK + total_samp_bytes;
  507.     update_form_chunk(&form_chunk);
  508.     update_comm_chunk(&comm_chunk);
  509.     update_ssnd_chunk(&ssnd_chunk);
  510.     close(fd);
  511. }
  512.  
  513. /*
  514.  * W R I T E _ F O R M _ C H U N K
  515.  */
  516. static void
  517. write_form_chunk(form_chunk_t *form_chunk)
  518. {
  519.     char buf[FORM_CHUNK];
  520.  
  521.     bzero(buf,FORM_CHUNK);
  522.     bcopy("FORM",buf,4);
  523.     bcopy("AIFF",buf+8,4);
  524.     write(fd,buf,FORM_CHUNK);
  525.     form_chunk->file_position = 0;
  526. }
  527.  
  528. /*
  529.  * W R I T E _ C O M M _ C H U N K 
  530.  */
  531. static void
  532. write_comm_chunk(comm_chunk_t *comm_chunk, sample *s)
  533. {
  534.     char buf[COMM_CHUNK];
  535.     int i;
  536.     char *bufp, *cp;
  537.     long tmplong;
  538.     short tmpshort;
  539.  
  540. /*
  541.  *    here is the structure of a COMM_CHUNK:
  542.  *        
  543.  *    0    char[4]        const "COMM"
  544.  *    4    long        const COMM_CHUNK_DATA
  545.  *    8    short        n channels
  546.  *    10    long         n sample frames
  547.  *    14    short         sample width
  548.  *    16    char[10]    80 bit floating point sample rate
  549.  */
  550.     bzero(buf,COMM_CHUNK);
  551.     bcopy("COMM",buf,4);             /* char[4] chunk id */
  552.     tmplong =  COMM_CHUNK_DATA;
  553.     bcopy(&tmplong,buf+4,sizeof(long));     /* long COMM_CHUNK_DATA */
  554.     tmpshort = s->nchannels;
  555.     bcopy(&tmpshort,buf+8,sizeof(short));     /* short nchannels */
  556.     tmplong = 0;    /* gets written later */
  557.     bcopy(&tmplong,buf+10,sizeof(long));     /* long sampleframes (later) */
  558.     tmpshort = 8*s->sampwidth;
  559.     bcopy(&tmpshort,buf+14,sizeof(short));     /* short sampwidth */
  560.     tmpshort = s->samprate;
  561.     cp = (char *)&tmpshort;             /* 10-bit extended samprate*/
  562.     bufp = buf+16;
  563.     /* 
  564.      * WOW!! this works: 80 bit floating point number follows 
  565.      */
  566.     *bufp++ =  0x40;
  567.     *bufp++ =  0x0e;
  568.     *bufp++ =  *cp++;
  569.     *bufp++ =  *cp;
  570.     /* the rest is already zero!! */
  571.  
  572.     comm_chunk->file_position = lseek(fd, 0, SEEK_CUR);
  573.     write(fd, buf, COMM_CHUNK);
  574. }
  575.  
  576. /*
  577.  * W R I T E _ S S N D _ C H U N K 
  578.  */
  579. static void
  580. write_ssnd_chunk(ssnd_chunk_t *ssnd_chunk)
  581. {
  582.     char buf[SSND_CHUNK];
  583.  
  584.     bzero(buf,SSND_CHUNK);
  585.     bcopy("SSND",buf,4);
  586.     ssnd_chunk->file_position = lseek(fd, 0, SEEK_CUR);
  587.     write(fd, buf, SSND_CHUNK);
  588. }
  589.  
  590. /*
  591.  *     save_audio
  592.  */
  593. static void
  594. write_audio(sample *s)
  595. {
  596.     int nbytes;
  597.     unsigned char *buf;
  598.     int samps_per_buf;
  599.     int bytes_per_buf;
  600.     int frames_per_buf;
  601.     int frames_per_sec;
  602.     int bytes_per_samp;
  603.     int samps_per_frame;
  604.     int togo, thistime;
  605.  
  606.     bytes_per_samp  = 2;  /* hardwire to 16-bit samples */
  607.     samps_per_frame = 2;  /* hardwire to stereo */
  608.     frames_per_sec  = ((float)s->samprate); 
  609.     frames_per_buf  = frames_per_sec / 2;
  610.     samps_per_buf   = frames_per_buf * samps_per_frame;
  611.     bytes_per_buf   = samps_per_buf * bytes_per_samp;
  612.     total_frames = 0;
  613.     total_samp_bytes = 0;
  614.     
  615.     /*
  616.      * we assume the file pointer now points to the beginning
  617.      * of the audio sample section of the AIFF file
  618.      */ 
  619.     togo = s->nsamples*s->sampwidth;
  620.     buf = (unsigned char *)s->data;
  621.     while(togo) {
  622.     thistime = bytes_per_buf;
  623.     if(thistime>togo)
  624.         thistime = togo;
  625.     if ((nbytes = write(fd, buf, thistime)) != thistime) {
  626.           fprintf(stderr,
  627.           "%s:  tried to write %d bytes to %s, actually wrote %d\n",
  628.            myname, thistime, filename, nbytes);
  629.         exit(1);
  630.     }
  631.     buf += thistime;
  632.         total_frames += (nbytes/(samps_per_frame*bytes_per_samp));
  633.         total_samp_bytes += nbytes;
  634.     togo -= thistime;
  635.     }
  636. }
  637.  
  638. /*
  639.  * U P D A T E _ F O R M _ C H U N K
  640.  */
  641. static void
  642. update_form_chunk(form_chunk_t *form_chunk)
  643. {
  644.     long seekpos;
  645.  
  646.     seekpos = form_chunk->file_position + 4;    /* seek past 4 id bytes */
  647.     lseek(fd, seekpos, SEEK_SET);
  648.     writelong(fd,total_bytes-CHUNK_HEADER);
  649. }
  650.  
  651. /*
  652.  * U P D A T E _ C O M M _ C H U N K
  653.  */
  654. static void 
  655. update_comm_chunk(comm_chunk_t *comm_chunk)
  656. {
  657.     long seekpos;
  658.  
  659.     seekpos = comm_chunk->file_position + CHUNK_HEADER + sizeof(short);
  660.     lseek(fd, seekpos, SEEK_SET);      
  661.     writelong(fd,total_frames);
  662.  
  663. }
  664.  
  665. /*
  666.  * U P D A T E _ S S N D _ C H U N K
  667.  */
  668. static void 
  669. update_ssnd_chunk(ssnd_chunk_t *ssnd_chunk)
  670. {
  671.     long seekpos;
  672.  
  673.     seekpos = ssnd_chunk->file_position + CHUNK_ID;
  674.     lseek(fd, seekpos, SEEK_SET);
  675.     writelong(fd,SSND_CHUNK_DATA + total_samp_bytes);
  676. }
  677.  
  678. writelong(fd,val)
  679. int fd;
  680. long val;
  681. {
  682.     write(fd, &val, sizeof(long));
  683. }
  684.  
  685. /*
  686.  *    ulitity functions follow
  687.  *
  688.  */
  689. static int firsted;
  690. static ALport audioport;
  691.  
  692. static writeaudio(data,nshorts,samprate)
  693. short *data;
  694. int nshorts, samprate;
  695. {
  696.     long pvbuf[2];
  697.     ALconfig portconfig;
  698.  
  699.     if(!firsted) {
  700.     pvbuf[0] = AL_OUTPUT_RATE;
  701.     pvbuf[1] = samprate;
  702.     ALsetparams(AL_DEFAULT_DEVICE,pvbuf,2);
  703.     portconfig = ALnewconfig();
  704.     ALsetwidth(portconfig,2);
  705.     ALsetchannels(portconfig,2);
  706.     audioport = ALopenport("name","w",portconfig);
  707.     firsted = 1;
  708.     }
  709.     if(!nshorts)
  710.     return;
  711.     ALwritesamps(audioport,data,nshorts);
  712. }
  713.  
  714. playsample(s)
  715. sample *s;
  716. {
  717.     playsubsample(s,0,s->nsamples-1);
  718. }
  719.  
  720. playsubsample(s,start,finish)
  721. sample *s;
  722. {
  723.     start = ilimit(0,start,s->nsamples-1);
  724.     finish = ilimit(0,finish,s->nsamples-1);
  725.     start &= 0xffffffe;
  726.     finish &= 0xffffffe;
  727.     writeaudio(s->data+start,finish-start+1,s->samprate);
  728. }
  729.  
  730. flushsample()
  731. {
  732.     if(firsted) {
  733.     while(ALgetfilled(audioport) > 0)
  734.         sginap(1);
  735.     }
  736. }
  737.  
  738. printsample(s)
  739. sample *s;
  740. {
  741.     int min, max;
  742.  
  743.     printf("\nsample rate: %d\n",s->samprate);
  744.     printf(" n channels: %d\n",s->nchannels);
  745.     printf(" samp width: %d\n",s->sampwidth);
  746.     printf(" n samples : %d\n",s->nsamples);
  747.     minmaxsample(s,&min,&max);
  748.     printf(" min val: %d\n",min);
  749.     printf(" max val: %d\n",max);
  750. }
  751.  
  752. expandsample(s)
  753. sample *s;
  754. {
  755.     int min, max, del;
  756.     int n;
  757.     short *sptr;
  758.  
  759.     minmaxsample(s,&min,&max);
  760.     if(min<0)
  761.        min = -min;
  762.     if(min>max)
  763.     max = min;
  764.     del = 2*max;
  765.     min = -max;
  766.  
  767.     if(del == 0)
  768.     return;
  769.     sptr = s->data;
  770.     n = s->nsamples;
  771.     while(n--) {
  772.     *sptr = ((((unsigned long)(*sptr-min))*64000)/del)-32000;
  773.      sptr++;
  774.     }
  775. }
  776.  
  777. float rmssample(s)
  778. sample *s;
  779. {
  780. }
  781.  
  782. minmaxsample(s,min,max)
  783. sample *s;
  784. int *min, *max;
  785. {
  786.     int n, smin, smax;
  787.     short *sptr;
  788.      
  789.     sptr = s->data;
  790.     n = s->nsamples;
  791.     smin = 40000;
  792.     smax = -40000;
  793.     while(n--) {
  794.     if(*sptr>smax)
  795.         smax = *sptr;
  796.     if(*sptr<smin)
  797.         smin = *sptr;
  798.     sptr++;
  799.     }
  800.     *min = smin;
  801.     *max = smax;
  802. }
  803.  
  804. scalesample(s,gain)
  805. sample *s;
  806. float gain;
  807. {
  808.     int val, n;
  809.     short *sptr;
  810.      
  811.     sptr = s->data;
  812.     n = s->nsamples;
  813.     while(n--) {
  814.     val = (*sptr * gain)+0.5;
  815.     if(val<-32000)
  816.         val = -32000;
  817.     if(val>32000)
  818.         val = 32000;
  819.     *sptr++ = val;
  820.     }
  821. }
  822.  
  823. float flerp();
  824.  
  825. stereoizesample(s,mag)
  826. sample *s;
  827. float mag;
  828. {
  829.     int nsamples;
  830.     int nframes;
  831.     float r, l, m;
  832.     short *sptr;
  833.  
  834.     nframes = s->nsamples/2;
  835.     sptr = s->data;
  836.     while(nframes--) {
  837.        r = sptr[0];
  838.        l = sptr[1];
  839.        m = (r+l)/2.0;
  840.        r = flerp(m,r,mag);
  841.        l = flerp(m,l,mag);
  842.        if(r<-32768) r = -32768;
  843.        if(r> 32767) r = 32767;
  844.        if(l<-32768) l = -32768;
  845.        if(l> 32767) l = 32767;
  846.        sptr[0] = r;
  847.        sptr[1] = l;
  848.        sptr+=2;
  849.     }
  850. }
  851.  
  852. freesample(s)
  853. sample *s;
  854. {
  855.     free(s->data);
  856.     free(s);
  857. }
  858.  
  859. sample *clonesample(s)
  860. sample *s;
  861. {
  862.     sample *cs;
  863.  
  864.     cs = (sample *)malloc(sizeof(struct sample));
  865.     *cs = *s;
  866.     cs->data = (short *)malloc(s->nsamples*sizeof(short));
  867.     bcopy(s->data,cs->data,s->nsamples*sizeof(short));
  868.     return cs;
  869. }
  870.  
  871. sample *tonesample(nsamples)
  872. int nsamples;
  873. {
  874.     sample *s;
  875.     short *sptr, val;
  876.     int i, frames;
  877.  
  878.     if(nsamples&1)
  879.        nsamples--;
  880.     s = (sample *)malloc(sizeof(struct sample));
  881.     s->samprate = 32000;
  882.     s->nchannels = 2;
  883.     s->sampwidth = 2;
  884.     s->nsamples = nsamples;
  885.     s->data = (short *)malloc(s->nsamples*sizeof(short));
  886.     sptr = s->data;
  887.     frames = nsamples/2;
  888.     for(i=0; i<frames; i++) {
  889.     val = 32000.0*sin(2.0*M_PI*i/frames);
  890.     *sptr++ = val;
  891.     *sptr++ = val;
  892.     }
  893.     return s;
  894. }
  895.  
  896. sample *subsample(s,begin,end)
  897. sample *s;
  898. int begin, end;
  899. {
  900.     int temp, len;
  901.     sample *cs;
  902.  
  903.     begin = ilimit(0,begin,s->nsamples-1);
  904.     end = ilimit(0,end,s->nsamples-1);
  905.     begin &= 0xffffffe;
  906.     end &= 0xffffffe;
  907.     if(end<begin) {
  908.     temp = end;
  909.     end = begin;
  910.     begin = temp;
  911.     }
  912.     len = end-begin+1;
  913.     cs = (sample *)malloc(sizeof(struct sample));
  914.     *cs = *s;
  915.     cs->nsamples = len;
  916.     cs->data = (short *)malloc(len*sizeof(short));
  917.     bcopy(s->data+begin,cs->data,len*sizeof(short));
  918.     return cs;
  919. }
  920.  
  921. sample *extendsample(s,len) 
  922. sample *s;
  923. int len;
  924. {
  925.     sample *cs;
  926.  
  927.     cs = (sample *)malloc(sizeof(struct sample));
  928.     *cs = *s;
  929.     cs->nsamples = len;
  930.     cs->data = (short *)malloc(len*sizeof(short));
  931.     bzero(cs->data,len*sizeof(short));
  932.     if(s->nsamples<len)
  933.        len = s->nsamples;
  934.     bcopy(s->data,cs->data,len*sizeof(short));
  935.     return cs;
  936. }
  937.  
  938. reversesample(s) 
  939. sample *s;
  940. {
  941.     int i, nframes;
  942.     short *sptr, *dptr, t;
  943.  
  944.     nframes = s->nsamples/s->nchannels;
  945.     sptr = s->data;
  946.     dptr = s->data+s->nchannels*nframes;
  947.     while(sptr<dptr) {
  948.     dptr -= s->nchannels;
  949.     for(i=0; i<s->nchannels; i++) {
  950.         t = sptr[i];
  951.         sptr[i] = dptr[i];
  952.         dptr[i] = t;
  953.     }
  954.     sptr += s->nchannels;
  955.     }
  956.  
  957. }
  958.  
  959. sample *addsample(s1,s2,offset)
  960. sample *s1, *s2;
  961. int offset;
  962. {
  963. #ifdef NOTDEF
  964.     int nsamples;
  965.     int min, max
  966.     sample *as;
  967.     short *aptr, *bptr, *sptr;
  968.     short p1, p2, s;
  969.     short v1, v2, s;
  970.  
  971.     if(offset<0) {
  972.     min = 0;
  973.     } else {
  974.     min = offset;
  975.     }
  976.     max = MAX(s1->nsamples,s2->nsamples+offset);
  977.     nsamples = max-min;
  978.     as = (sample *)malloc(sizeof(struct sample));
  979.     *as = *s1;
  980.     as->nsamples = nsamples;
  981.     as->data = (short *)malloc(nsamples*sizeof(short));
  982.     for(i=min; i<max; i++) {
  983.     p1 = 
  984.     if(i<0
  985.     a = s1
  986.     }
  987. #endif
  988. }
  989.  
  990. /* XXX graphic equalizer someday*/
  991.  
  992. /* 
  993.  *    support for playing simultaneous notes follows 
  994.  *
  995.  */
  996. dprintf()
  997. {
  998. }
  999.  
  1000. static int curtime = 0;
  1001.  
  1002. typedef struct activesample {
  1003.     struct activesample *next;
  1004.     sample *s;
  1005.     int tmin;
  1006.     int tmax;
  1007.     float amplitude;
  1008. } activesample;
  1009.  
  1010. #define CHUNKSIZE    (1000)
  1011. #define FOREVER        (1000000000)
  1012.  
  1013. static activesample *active;
  1014. static float *fbuf;
  1015. static short *sbuf;
  1016. static float bpm = 120.0;
  1017. static float humanamp = 0.0;
  1018. static float humantime = 0.0;
  1019.  
  1020. beginnotes()
  1021. {
  1022.     curtime = 0;
  1023.     active = 0;
  1024. }
  1025.  
  1026. endnotes()
  1027. {
  1028.     flushnotes(1000000.0);
  1029.     flushsample();
  1030. }
  1031.  
  1032. setbpm(b)
  1033. float b;
  1034. {
  1035.     bpm = b;
  1036. }
  1037.  
  1038. sethumanize(t,a)
  1039. float t, a;
  1040. {
  1041.     humantime = t;
  1042.     humanamp = a;
  1043. }
  1044.  
  1045. float frand();
  1046.  
  1047. playnote(s,ftime,amplitude)
  1048. sample *s;
  1049. float ftime;
  1050. float amplitude;
  1051. {
  1052.     activesample *as;
  1053.     int time;
  1054.  
  1055.     ftime = ftime+(humantime*(frand()-0.5));
  1056.     time = ftime*(60.0/bpm)*s->samprate;
  1057.     if(time<0.0)
  1058.     time = 0.0;
  1059.     if(time<curtime) {
  1060.     fprintf(stderr,"putsample: start times must be increasing\n");
  1061.     fprintf(stderr,"time is %d, curtime is %d\n",time,curtime);
  1062.     return;
  1063.     }
  1064.     as = (activesample *)malloc(sizeof(activesample));
  1065.     as->s = s;
  1066.     as->tmin = time;
  1067.     as->tmax = time+(s->nsamples/2);
  1068.     as->amplitude = amplitude*(1.0-humanamp*frand());
  1069.  
  1070. /* add the sample to the active list */
  1071.     as->next = active;
  1072.     active = as;
  1073. }
  1074.  
  1075. flushnotes(ftime)
  1076. float ftime;
  1077. {
  1078.     int time;
  1079.     activesample *as, *temp;
  1080.     int mint, nplay, thistime, n;
  1081.     int div, val;
  1082.     short *sptr;
  1083.     float *fptr;
  1084.     float amp;
  1085.  
  1086.     if(!active)
  1087.     return;
  1088.     time = ftime*(60.0/bpm)*active->s->samprate;
  1089.     time -= CHUNKSIZE;    /* XXXXX */
  1090.     if(!sbuf) {
  1091.     fbuf = (float *)malloc(2*CHUNKSIZE*sizeof(float));
  1092.     sbuf = (short *)malloc(2*CHUNKSIZE*sizeof(short));
  1093.     }
  1094. dprintf("A curtime %d\n",curtime);
  1095.     while(active && curtime<time) {
  1096.  
  1097. /* figure out how many samples we can put out before change in samples  */
  1098.     mint = FOREVER;
  1099.     as = active;
  1100.     while(as) {
  1101.         if(curtime<as->tmin) {
  1102.         if(mint>as->tmin)
  1103.             mint = as->tmin;
  1104.         } else if(curtime<as->tmax) {
  1105.         if(mint>as->tmax)
  1106.             mint = as->tmax;
  1107.         }
  1108.         as = as->next;
  1109.     }
  1110.     nplay = mint - curtime;
  1111.     if(nplay>CHUNKSIZE)
  1112.         nplay = CHUNKSIZE;
  1113.  
  1114. /* clear the accumulator */
  1115.     bzero(fbuf,2*nplay*sizeof(float));
  1116.  
  1117. /* accumulate the active samples */
  1118.     div = 0;
  1119.     as = active;
  1120.     while(as) {
  1121.         if((as->tmin<curtime+nplay) && (as->tmax>curtime)) {
  1122.         fptr = fbuf;
  1123.         sptr = as->s->data+2*(curtime-as->tmin);
  1124.         amp = as->amplitude;
  1125.         n = 2*nplay;
  1126.         while(n--) {
  1127.             *fptr = *fptr + amp*(*sptr++);
  1128.             fptr++;
  1129.         }
  1130.         div++;
  1131.         }
  1132.         as = as->next;
  1133.     }
  1134.  
  1135. /* copy and range check */
  1136.     fptr = fbuf;
  1137.     sptr = sbuf;
  1138.     n = 2*nplay;
  1139.     while(n--) {
  1140.         val = *fptr++;
  1141.         if(val<-32000)
  1142.         *sptr++ = -32000;
  1143.         else if(val>32000)
  1144.         *sptr++ = 32000;
  1145.         else
  1146.         *sptr++ = val;
  1147.     }
  1148.  
  1149. /* play the sum of the active samples */
  1150.     writeaudio(sbuf,2*nplay,active->s->samprate);
  1151.  
  1152. /* update the time */
  1153.     curtime += nplay;
  1154.  
  1155. /* remove old samples */
  1156.     for( as = (activesample *)&active; as->next; )  {
  1157.         if (as->next->tmax <= curtime) {
  1158.         temp = as->next;
  1159.         as->next = temp->next;
  1160.         free(temp);
  1161.         } else
  1162.         as = as->next;
  1163.     }
  1164.     }
  1165. }
  1166.